#include <iostream>
#include <functional>
#include <memory>
#include <vector>
#include <unordered_map>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &task) : _id(id), _timeout(delay), _task(task), _cancel(false)
    {
    }

    void Cancel() { _cancel = true; }
    void SetRelease(const ReleaseFunc &release) { _release = release; }
    uint32_t DelayTime() { return _timeout; }

    ~TimerTask()
    {
        if (!_cancel) _task();
        _release();
    }

private:
    uint64_t _id;         // 任务id
    TaskFunc _task;       // 定时任务
    ReleaseFunc _release; // 销毁定时任务
    bool _cancel;         // 任务是否被取消
    uint32_t _timeout;    // 定时任务的超时时间
};

#define MAX_DELAY 60

class TimerWheel
{
public:
    using TaskPtr = std::shared_ptr<TimerTask>;
    using WeakTaskPtr = std::weak_ptr<TimerTask>;
    TimerWheel() : _capacity(MAX_DELAY), _tick(0), _wheel(_capacity) {}

    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc &task)
    {
        TaskPtr tp = std::make_shared<TimerTask>(id, timeout, task);
        tp->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        _timers.insert({id, WeakTaskPtr(tp)});
        int pos = (_tick + timeout) % _capacity;
        _wheel[pos].push_back(tp);
    }

    // 刷新定时任务
    void TimerRefresh(uint64_t id)
    {
        // 通过保存的定时器对象的 weak_ptr 然后实例化一个 shared_ptr 出来，添加到 wheel中 这样就是增加同一个引用计数了
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        TaskPtr tp = it->second.lock();
        int delay = tp->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(tp);
    }

    // 取消定时任务
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        TaskPtr tp = it->second.lock();
        tp->Cancel();
    }

    // 这个函数应该每秒钟执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _wheel[_tick].clear();
        _tick = (_tick + 1) % _capacity;
    }

private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

private:
    int _capacity;
    int _tick;
    std::vector<std::vector<TaskPtr>> _wheel;
    std::unordered_map<uint64_t, WeakTaskPtr> _timers; // 所有定时器的 weak_ptr 对象 构造出新的 share_ptr 共享计数
};

class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void DelTest(Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();

    tw.TimerAdd(888, 5, std::bind(DelTest, t));

    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(888); // 刷新定时任务
        tw.RunTimerTask();    // 向后移动秒针
        std::cout << "刷新了一下定时任务，需要5s钟后才会销毁\n";
    }

    // 测试取消
    tw.TimerCancel(888);

    while (true)
    {
        sleep(1);
        std::cout << "-----------------------\n";
        tw.RunTimerTask(); // 向后移动秒针
    }

    return 0;
}